<template>
  <div class="workspace-management">
    <!-- 没有工作区时显示创建工作区界面 -->
    <div v-if="!hasWorkspaces" class="create-workspace-section">
      <div class="create-workspace-form">
        <div class="form-header">
          <div class="header-icon">
            <n-icon size="48" color="#18a058">
              <CogOutline />
            </n-icon>
          </div>
          <h2>创建工作区</h2>
          <p>创建一个新的工作区来开始您的日志分析工作</p>
        </div>
        
        <n-form 
          :model="newWorkspace" 
          :rules="workspaceRules" 
          ref="formRef"
          class="workspace-form"
        >
                     <n-form-item label="工作区名称" path="name">
             <n-input 
               v-model:value="newWorkspace.name" 
               placeholder="请输入工作区名称，建议以服务器IP命名"
               size="large"

             />
           </n-form-item>
          
          <n-form-item label="导入日志文件" path="logFiles">
            <div class="upload-section">
              <n-upload
                v-model:file-list="fileList"
                :multiple="false"
                :accept="'.gz'"
                :max="1"
                @change="handleFileChange"
                @remove="handleFileRemove"
              >
                <n-upload-dragger>
                  <div class="upload-content">
                    <n-icon size="48" color="#d9d9d9">
                      <DocumentOutline />
                    </n-icon>
                                         <p class="upload-text">点击或拖拽gz压缩包文件到此处</p>
                     <p class="upload-hint">支持 .gz 格式的压缩包文件，将自动解压</p>
                  </div>
                </n-upload-dragger>
              </n-upload>
              
              <div v-if="fileList.length > 0" class="file-info">
                <n-tag type="success" size="small">
                  <template #icon>
                    <n-icon><DocumentOutline /></n-icon>
                  </template>
                  {{ fileList[0].name }}
                </n-tag>
              </div>
            </div>
          </n-form-item>
          
          <n-form-item>
            <n-button 
              type="primary" 
              size="large" 
              @click="createWorkspace"
              :disabled="!canCreate"
              :loading="isCreating"
              block
            >
              <template #icon>
                <n-icon v-if="!isCreating"><AddOutline /></n-icon>
              </template>
              {{ isCreating ? '创建中...' : '创建工作区' }}
            </n-button>
          </n-form-item>
        </n-form>
      </div>
    </div>

    <!-- 有工作区时显示工作区管理界面 -->
    <div v-else class="workspace-overview-section">
      <div class="page-header">
        <div class="header-content">
          <div class="title-section">
            <h1>工作区管理</h1>
            <p class="subtitle">管理所有日志分析工作区，查看统计信息和切换工作区</p>
          </div>
          <div class="header-actions">
            <n-button type="primary" @click="showCreateWorkspace = true">
              <template #icon>
                <n-icon><AddOutline /></n-icon>
              </template>
              新建工作区
            </n-button>
          </div>
        </div>
      </div>

      <!-- 工作区概览 -->
      <div class="workspace-overview">
        <n-grid :cols="3" :x-gap="16" :y-gap="16">
          <n-grid-item v-for="workspace in workspaceStore.workspaces" :key="workspace.id">
            <n-card 
              :class="['workspace-card', { 'active': workspace.id === workspaceStore.currentWorkspaceId }]"
              @click="selectWorkspace(workspace.id)"
            >
              <div class="workspace-card-header">
                <div class="workspace-info">
                  <h3>{{ workspace.name }}</h3>
                  <p>{{ workspace.description }}</p>
                  <n-tag :type="workspace.status === 'active' ? 'success' : 'warning'" size="small">
                    {{ workspace.status === 'active' ? '活跃' : '停用' }}
                  </n-tag>
                </div>
                <div class="workspace-actions">
                  <n-button 
                    size="small" 
                    type="primary" 
                    @click.stop="enterWorkspace(workspace.id)"
                  >
                    进入工作区
                  </n-button>
                </div>
              </div>
              
              <div class="workspace-stats">
                <div class="stat-item">
                  <span class="stat-label">日志文件</span>
                  <span class="stat-value">{{ workspace.stats.logFiles }}</span>
                </div>
                <div class="stat-item">
                  <span class="stat-label">分析任务</span>
                  <span class="stat-value">{{ workspace.stats.analysisTasks }}</span>
                </div>
                <div class="stat-item">
                  <span class="stat-label">创建时间</span>
                  <span class="stat-value">{{ formatDate(workspace.createTime) }}</span>
                </div>
              </div>
            </n-card>
          </n-grid-item>
        </n-grid>
      </div>

      <!-- 当前工作区功能入口 -->
      <div v-if="workspaceStore.currentWorkspace" class="current-workspace-section">
        <n-card title="当前工作区功能">
          <template #header-extra>
            <n-tag type="success">{{ workspaceStore.currentWorkspace.name }}</n-tag>
          </template>
          
          <n-grid :cols="5" :x-gap="16" :y-gap="16">
            <n-grid-item>
              <n-card title="本地日志查看" class="feature-card" size="small">
                <template #header-extra>
                  <n-button size="tiny" @click="router.push('/workspace/viewer')" type="primary">
                    进入
                  </n-button>
                </template>
                <p>查看和分析已导入的日志</p>
              </n-card>
            </n-grid-item>
                         <n-grid-item>
               <n-card title="日志转储管理" class="feature-card" size="small">
                 <template #header-extra>
                   <n-button size="tiny" @click="router.push('/workspace/dump')" type="primary">
                     进入
                   </n-button>
                 </template>
                 <p>管理日志转储文件和策略</p>
               </n-card>
             </n-grid-item>
            <n-grid-item>
              <n-card title="智能分析" class="feature-card" size="small">
                                <template #header-extra>
                  <n-button size="tiny" @click="router.push('/workspace/analysis')" type="primary">
                    进入
                  </n-button>
                </template>
                <p>AI驱动的智能分析</p>
              </n-card>
            </n-grid-item>
            <n-grid-item>
              <n-card title="可视化" class="feature-card" size="small">
                <template #header-extra>
                  <n-button size="tiny" @click="router.push('/workspace/visualization')" type="primary">
                    进入
                  </n-button>
                </template>
                <p>数据图表和可视化</p>
              </n-card>
            </n-grid-item>
            <n-grid-item>
              <n-card title="报表" class="feature-card" size="small">
                <template #header-extra>
                  <n-button size="tiny" @click="router.push('/workspace/reports')" type="primary">
                    进入
                  </n-button>
                </template>
                <p>生成分析报表</p>
              </n-card>
            </n-grid-item>
            <n-grid-item>
              <n-card title="调试分析" class="feature-card" size="small">
                <template #header-extra>
                  <n-button size="tiny" @click="router.push('/debug-analysis')" type="warning">
                    进入
                  </n-button>
                </template>
                <p>分析 tauri dev 和 build 差异</p>
              </n-card>
            </n-grid-item>
          </n-grid>
        </n-card>
      </div>
    </div>

    <!-- 创建工作区对话框（有工作区时使用） -->
    <n-modal v-model:show="showCreateWorkspace" preset="card" title="创建新工作区" style="width: 600px">
      <n-form :model="newWorkspace" :rules="workspaceRules" ref="modalFormRef">
                 <n-form-item label="工作区名称" path="name">
           <n-input v-model:value="newWorkspace.name" placeholder="请输入工作区名称，建议以服务器IP命名" />
         </n-form-item>

        <n-form-item label="导入日志文件" path="logFiles">
          <n-upload
            v-model:file-list="modalFileList"
            :multiple="false"
            :accept="'.gz'"
            :max="1"
            @change="handleModalFileChange"
            @remove="handleModalFileRemove"
          >
            <n-upload-dragger>
              <div class="upload-content">
                <n-icon size="32" color="#d9d9d9">
                  <DocumentOutline />
                </n-icon>
                                 <p class="upload-text">点击或拖拽gz压缩包文件到此处，将自动解压</p>
               </div>
            </n-upload-dragger>
          </n-upload>
        </n-form-item>
      </n-form>
      <template #footer>
        <n-space justify="end">
          <n-button @click="showCreateWorkspace = false" :disabled="isCreating">取消</n-button>
          <n-button type="primary" @click="createWorkspaceFromModal" :loading="isCreating" :disabled="isCreating">
            {{ isCreating ? '创建中...' : '创建' }}
          </n-button>
        </n-space>
      </template>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { AddOutline, CogOutline, DocumentOutline } from '@vicons/ionicons5'
import { useWorkspaceStore } from '../stores/workspace'
import { useFileDataStore } from '../stores/fileData'
import type { UploadFileInfo } from 'naive-ui'
import pako from 'pako'
import { saveWorkspaceEntries } from '../utils/archiveDb'

const router = useRouter()
const workspaceStore = useWorkspaceStore()
const fileDataStore = useFileDataStore()

// 响应式数据
const showCreateWorkspace = ref(false)
const fileList = ref<UploadFileInfo[]>([])
const modalFileList = ref<UploadFileInfo[]>([])
const isCreating = ref(false)

// 计算是否有工作区
const hasWorkspaces = computed(() => workspaceStore.workspaces.length > 0)

// 计算是否可以创建工作区
const canCreate = computed(() => {
  return newWorkspace.name.trim() !== '' && fileList.value.length > 0 && !isCreating.value
})

// 新工作区表单
const newWorkspace = reactive({
  name: '',
  type: 'general'
})

// 表单验证规则
const workspaceRules = {
  name: {
    required: true,
    message: '请输入工作区名称',
    trigger: 'blur',
    validator: (rule: any, value: string) => {
      if (!value) {
        return new Error('请输入工作区名称')
      }
      // 检查是否以数字或字母开头
      if (!/^[a-zA-Z0-9]/.test(value)) {
        return new Error('工作区名称必须以字母或数字开头')
      }
      // 检查是否只包含字母、数字、点、下划线
      if (!/^[a-zA-Z0-9._]+$/.test(value)) {
        return new Error('工作区名称只能包含字母、数字、点(.)、下划线(_)')
      }
      return true
    }
  },
  logFiles: {
    required: true,
    message: '请导入日志文件',
    trigger: 'change'
  }
}

// 调试信息
onMounted(() => {
  console.log('=== Workspace管理页面已加载 ===')
  console.log('workspaceStore:', workspaceStore)
  console.log('workspaces:', workspaceStore.workspaces)
  console.log('hasWorkspaces:', hasWorkspaces.value)
  console.log('currentWorkspace:', workspaceStore.currentWorkspace)
  console.log('localStorage workspaces:', localStorage.getItem('workspaces'))
  console.log('localStorage currentWorkspaceId:', localStorage.getItem('currentWorkspaceId'))
  
  // 添加页面卸载时的清理逻辑
  window.addEventListener('beforeunload', () => {
    isCreating.value = false
  })
})

// 文件处理方法
function handleFileChange(options: { fileList: UploadFileInfo[] }) {
  console.log('=== 文件变化事件 ===')
  console.log('文件列表:', options.fileList)
  console.log('文件数量:', options.fileList.length)
  fileList.value = options.fileList
  
  // 如果有文件，自动解压
  if (options.fileList.length > 0) {
    const file = options.fileList[0]
    console.log('第一个文件:', file)
    console.log('文件名:', file.name)
    console.log('文件对象:', file.file)
    
    if (file.file && file.name.endsWith('.gz')) {
      console.log('检测到gz文件，开始自动解压:', file.name)
      extractGzFile(file.file)
    } else {
      console.log('文件不是gz格式或没有文件对象')
    }
  }
}

function handleFileRemove(options: { fileList: UploadFileInfo[] }) {
  console.log('文件移除:', options.fileList)
  fileList.value = options.fileList
}

function handleModalFileChange(options: { fileList: UploadFileInfo[] }) {
  console.log('模态框文件变化:', options.fileList)
  modalFileList.value = options.fileList
  
  // 如果有文件，自动解压
  if (options.fileList.length > 0) {
    const file = options.fileList[0]
    if (file.file && file.name.endsWith('.gz')) {
      console.log('检测到gz文件，开始自动解压:', file.name)
      extractModalGzFile(file.file)
    }
  }
}

function handleModalFileRemove(options: { fileList: UploadFileInfo[] }) {
  console.log('模态框文件移除:', options.fileList)
  modalFileList.value = options.fileList
}

// 方法
function selectWorkspace(workspaceId: string) {
  console.log('选择工作区:', workspaceId)
  workspaceStore.setCurrentWorkspace(workspaceId)
}

function enterWorkspace(workspaceId: string) {
  console.log('进入工作区:', workspaceId)
  workspaceStore.setCurrentWorkspace(workspaceId)
  // 默认进入日志导入页面
  router.push('/workspace/import')
}

async function createWorkspace() {
  console.log('=== 创建新工作区 ===')
  console.log('工作区数据:', newWorkspace)
  console.log('选择的文件:', fileList.value)
  console.log('canCreate:', canCreate.value)
  
  if (!canCreate.value) {
    console.warn('表单验证失败，无法创建工作区')
    console.warn('工作区名称:', newWorkspace.name.trim())
    console.warn('文件数量:', fileList.value.length)
    return
  }
  
  isCreating.value = true
  
  try {
    // 获取解压后的文件内容
    let extractedContent = ''
    let absolutePath = '' // 🔥 声明绝对路径变量
    if (fileList.value[0]?.file) {
      try {
        console.log('开始处理文件:', fileList.value[0].name)
        
        // 🔥 先将原始文件复制到data目录
        const originalFile = fileList.value[0].file
        const targetPath = `data/${originalFile.name}`
        console.log('准备复制文件到:', targetPath)
        
        // 使用Tauri的fs插件复制文件
        console.log('=== Tauri环境检测 ===')
        console.log('window.__TAURI__:', typeof window !== 'undefined' && (window as any).__TAURI__)
        console.log('process.versions.tauri:', (window as any).process?.versions?.tauri)
        
        if (typeof window !== 'undefined' && (window as any).__TAURI__) {
          try {
            console.log('=== 开始Tauri文件复制 ===')
            
            // 直接使用 Tauri 全局对象
            console.log('=== 使用 Tauri 全局对象 ===')
            
            const tauri = (window as any).__TAURI__
            if (!tauri) {
              throw new Error('Tauri 环境不可用')
            }
            
            console.log('Tauri 对象:', tauri)
            console.log('Tauri 的所有属性:', Object.keys(tauri))
            
            // 检查是否有 fs 和 path 插件
            if (!tauri.fs || !tauri.path) {
              throw new Error('Tauri fs 或 path 插件不可用')
            }
            
            const fs = tauri.fs
            const path = tauri.path
            
            console.log('fs 插件:', fs)
            console.log('path 插件:', path)
            console.log('fs 的所有属性:', Object.keys(fs))
            console.log('fs.createDir 类型:', typeof fs.createDir)
            console.log('fs.createDir 值:', fs.createDir)
            
            // 直接使用正确的函数名
            console.log('fs.mkdir 存在:', 'mkdir' in fs)
            console.log('fs.mkdir 类型:', typeof fs.mkdir)
            
            // Tauri fs 插件中，创建目录的函数是 mkdir
            const createDirFunc = fs.mkdir
            if (!createDirFunc || typeof createDirFunc !== 'function') {
              throw new Error(`mkdir 不是函数，实际类型: ${typeof fs.mkdir}`)
            }
            
            console.log('使用的创建目录函数:', createDirFunc)
            
            // 检查 fs 对象的实际结构
            console.log('fs 对象:', fs)
            console.log('fs 的所有属性:', Object.keys(fs))
            console.log('fs.createDir 类型:', typeof fs.createDir)
            console.log('fs.createDir 值:', fs.createDir)
            
            console.log('fs 对象:', fs)
            console.log('path 对象:', path)
            console.log('fs 的所有属性:', Object.keys(fs))
            console.log('fs.createDir 类型:', typeof fs.createDir)
            console.log('fs.createDir 值:', fs.createDir)
            
            const appDataDir = await path.appDataDir()
            console.log('appDataDir:', appDataDir)
            
            const targetDir = await path.join(appDataDir, 'data')
            const targetFile = await path.join(targetDir, originalFile.name)
            console.log('目标目录:', targetDir)
            console.log('目标文件:', targetFile)
            
            // 确保目标目录存在
            await createDirFunc(targetDir, { recursive: true })
            console.log('目标目录创建/确认成功')
            
            // 将File对象转换为临时文件，然后复制
            const tempPath = await path.tempDir()
            const tempFile = await path.join(tempPath, originalFile.name)
            console.log('临时文件路径:', tempFile)
            
            // 写入临时文件
            const arrayBuffer = await originalFile.arrayBuffer()
            console.log('文件读取完成，大小:', arrayBuffer.byteLength)
            
            // 使用 writeFile 而不是 writeBinaryFile
            console.log('fs.writeFile 类型:', typeof fs.writeFile)
            if (typeof fs.writeFile !== 'function') {
              throw new Error(`writeFile 不是函数，实际类型: ${typeof fs.writeFile}`)
            }
            await fs.writeFile(tempFile, new Uint8Array(arrayBuffer))
            console.log('临时文件写入成功')
            
            // 复制到目标位置
            if (typeof fs.copyFile !== 'function') {
              throw new Error(`copyFile 不是函数，实际类型: ${typeof fs.copyFile}`)
            }
            await fs.copyFile(tempFile, targetFile)
            console.log('文件复制成功:', targetFile)
            
            // 更新工作区文件路径为绝对路径
            absolutePath = targetFile
            console.log('绝对路径设置成功:', absolutePath)
            
          } catch (fsError) {
            console.error('Tauri文件复制失败，详细错误:', fsError)
            console.error('错误堆栈:', fsError.stack)
            console.warn('文件复制失败，将使用相对路径')
          }
        } else {
          console.warn('Tauri环境不可用，跳过文件复制')
        }
        
        extractedContent = await extractGzFile(originalFile)
        console.log('文件处理成功，大小:', (extractedContent.length / 1024 / 1024).toFixed(2), 'MB')
        
        // 不再在此处截断解压后的内容，确保可完整解析日志
        
        console.log('文件内容预览:', extractedContent.substring(0, 200) + '...')
      } catch (error) {
        console.error('文件处理失败:', error)
        throw new Error(`文件处理失败: ${error}`)
      }
    }
    
    // 使用store创建新工作区
    console.log('=== 创建工作区前的路径信息 ===')
    console.log('absolutePath:', absolutePath)
    console.log('fallback path:', `data/${fileList.value[0]?.name || ''}`)
    console.log('最终使用的 filePath:', absolutePath || `data/${fileList.value[0]?.name || ''}`)
    
    const workspace = workspaceStore.createWorkspace({
      name: newWorkspace.name,
      description: `工作区：${newWorkspace.name}`,
      type: newWorkspace.type,
      status: 'active',
      filePath: absolutePath || `data/${fileList.value[0]?.name || ''}`, // 优先使用绝对路径
      extractedData: extractedContent
    })
    
    console.log('=== 工作区创建后的信息 ===')
    console.log('工作区 filePath:', workspace.filePath)
    console.log('工作区 ID:', workspace.id)
    

    
    console.log('工作区创建成功:', workspace)
    
    // 切换到新创建的工作区
    workspaceStore.setCurrentWorkspace(workspace.id)
    
    // 重置表单
    newWorkspace.name = ''
    newWorkspace.type = 'general'
    fileList.value = []
    
    console.log('准备跳转到日志查看页面')
    
    // 立即跳转到日志查看页面，不等待数据保存完成
    router.push('/workspace/viewer')
    
    // 异步处理数据保存，避免阻塞页面跳转
    setTimeout(async () => {
      // 将大文件数据保存到专门的文件数据store中
      if (extractedContent) {
        try {
          console.log('=== 异步保存文件数据 ===')
          await fileDataStore.setFileData(workspace.id, extractedContent)
          console.log('异步文件数据保存成功')
        } catch (error) {
          console.error('异步文件数据保存失败:', error)
        }
      }
      
      // 若存在待持久化的 entries，则写入 IndexedDB
      try {
        const pending = (window as any).__lvPendingEntries as { path: string; type: 'file' | 'dir'; isBinary: boolean; bytes?: Uint8Array }[] | undefined
        if (pending && pending.length > 0) {
          console.log('异步开始持久化解压条目数量:', pending.length)
          await saveWorkspaceEntries(workspace.id, pending)
          console.log('异步持久化完成')
          ;(window as any).__lvPendingEntries = undefined
        }
      } catch (e) {
        console.error('异步持久化解压条目失败:', e)
      }
    }, 100)
  } catch (error) {
    console.error('创建工作区失败:', error)
    
    // 显示用户友好的错误信息
    const errorMessage = error instanceof Error ? error.message : '未知错误'
    alert(`创建工作区失败: ${errorMessage}`)
  } finally {
    isCreating.value = false
  }
}

async function createWorkspaceFromModal() {
  console.log('从模态框创建新工作区:', newWorkspace)
  console.log('选择的文件:', modalFileList.value)
  
  if (!newWorkspace.name.trim() || modalFileList.value.length === 0) {
    console.warn('表单验证失败，无法创建工作区')
    return
  }
  
  isCreating.value = true
  
  try {
  
  // 获取解压后的文件内容
  let extractedContent = ''
  let absolutePath = '' // 🔥 声明绝对路径变量
  if (modalFileList.value[0]?.file) {
    try {
      console.log('模态框开始处理文件:', modalFileList.value[0].name)
      
      // 🔥 先将原始文件复制到data目录
      const originalFile = modalFileList.value[0].file
      console.log('准备复制模态框文件到data目录:', originalFile.name)
      
      // 使用Tauri的fs插件复制文件
      console.log('=== 模态框Tauri环境检测 ===')
      console.log('window.__TAURI__:', typeof window !== 'undefined' && (window as any).__TAURI__)
      console.log('process.versions.tauri:', (window as any).process?.versions?.tauri)
      
      if (typeof window !== 'undefined' && (window as any).__TAURI__) {
        try {
          console.log('=== 模态框开始Tauri文件复制 ===')
          
          // 直接使用 Tauri 全局对象
          console.log('=== 模态框使用 Tauri 全局对象 ===')
          
          const tauri = (window as any).__TAURI__
          if (!tauri) {
            throw new Error('Tauri 环境不可用')
          }
          
          console.log('模态框Tauri 对象:', tauri)
          console.log('模态框Tauri 的所有属性:', Object.keys(tauri))
          
          // 检查是否有 fs 和 path 插件
          if (!tauri.fs || !tauri.path) {
            throw new Error('Tauri fs 或 path 插件不可用')
          }
          
          const fs = tauri.fs
          const path = tauri.path
          
          console.log('模态框fs 插件:', fs)
          console.log('模态框path 插件:', path)
          console.log('模态框fs 的所有属性:', Object.keys(fs))
          console.log('模态框fs.createDir 类型:', typeof fs.createDir)
          console.log('模态框fs.createDir 值:', fs.createDir)
          
          // 直接使用正确的函数名
          console.log('模态框fs.mkdir 存在:', 'mkdir' in fs)
          console.log('模态框fs.mkdir 类型:', typeof fs.mkdir)
          
          // Tauri fs 插件中，创建目录的函数是 mkdir
          const createDirFunc = fs.mkdir
          if (!createDirFunc || typeof createDirFunc !== 'function') {
            throw new Error(`模态框mkdir 不是函数，实际类型: ${typeof fs.mkdir}`)
          }
          
          console.log('模态框使用的创建目录函数:', createDirFunc)
          
          // 检查 fs 对象的实际结构
          console.log('模态框fs 对象:', fs)
          console.log('模态框fs 的所有属性:', Object.keys(fs))
          console.log('模态框fs.createDir 类型:', typeof fs.createDir)
          console.log('模态框fs.createDir 值:', fs.createDir)
          
          console.log('模态框fs 对象:', fs)
          console.log('模态框path 对象:', path)
          console.log('模态框fs 的所有属性:', Object.keys(fs))
          console.log('模态框fs.createDir 类型:', typeof fs.createDir)
          console.log('模态框fs.createDir 值:', fs.createDir)
          
          const appDataDir = await path.appDataDir()
          console.log('模态框appDataDir:', appDataDir)
          
          const targetDir = await path.join(appDataDir, 'data')
          const targetFile = await path.join(targetDir, originalFile.name)
          console.log('模态框目标目录:', targetDir)
          console.log('模态框目标文件:', targetFile)
          
          // 确保目标目录存在
          await createDirFunc(targetDir, { recursive: true })
          console.log('模态框目标目录创建/确认成功')
          
          // 将File对象转换为临时文件，然后复制
          const tempPath = await path.tempDir()
          const tempFile = await path.join(tempPath, originalFile.name)
          console.log('模态框临时文件路径:', tempFile)
          
          // 写入临时文件
          const arrayBuffer = await originalFile.arrayBuffer()
          console.log('模态框文件读取完成，大小:', arrayBuffer.byteLength)
          
          // 使用 writeFile 而不是 writeBinaryFile
          console.log('模态框fs.writeFile 类型:', typeof fs.writeFile)
          if (typeof fs.writeFile !== 'function') {
            throw new Error(`模态框writeFile 不是函数，实际类型: ${typeof fs.writeFile}`)
          }
          await fs.writeFile(tempFile, new Uint8Array(arrayBuffer))
          console.log('模态框临时文件写入成功')
          
          // 复制到目标位置
          if (typeof fs.copyFile !== 'function') {
            throw new Error(`copyFile 不是函数，实际类型: ${typeof fs.copyFile}`)
          }
          await fs.copyFile(tempFile, targetFile)
          console.log('模态框文件复制成功:', targetFile)
          
          // 更新工作区文件路径为绝对路径
          absolutePath = targetFile
          console.log('模态框绝对路径设置成功:', absolutePath)
          
        } catch (fsError) {
          console.error('模态框Tauri文件复制失败，详细错误:', fsError)
          console.error('错误堆栈:', fsError.stack)
          console.warn('模态框文件复制失败，将使用相对路径')
        }
      } else {
        console.warn('模态框Tauri环境不可用，跳过文件复制')
      }
      
      extractedContent = await extractGzFile(originalFile)
      console.log('模态框文件处理成功，大小:', (extractedContent.length / 1024 / 1024).toFixed(2), 'MB')
      
      // 不再在此处截断解压后的内容，确保可完整解析日志
      
      console.log('模态框文件内容预览:', extractedContent.substring(0, 200) + '...')
    } catch (error) {
      console.error('模态框文件处理失败:', error)
      throw new Error(`文件处理失败: ${error}`)
    }
  }
  
  // 使用store创建新工作区
  console.log('=== 模态框创建工作区前的路径信息 ===')
  console.log('absolutePath:', absolutePath)
  console.log('fallback path:', `data/${modalFileList.value[0]?.name || ''}`)
  console.log('最终使用的 filePath:', absolutePath || `data/${modalFileList.value[0]?.name || ''}`)
  
  const workspace = workspaceStore.createWorkspace({
    name: newWorkspace.name,
    description: `工作区：${newWorkspace.name}`,
    type: newWorkspace.type,
    status: 'active',
    filePath: absolutePath || `data/${modalFileList.value[0]?.name || ''}`, // 优先使用绝对路径
    extractedData: extractedContent
  })
  
  console.log('=== 模态框工作区创建后的信息 ===')
  console.log('工作区 filePath:', workspace.filePath)
  console.log('工作区 ID:', workspace.id)
  
  // 将大文件数据保存到专门的文件数据store中（不再截断）
  if (extractedContent) {
    await fileDataStore.setFileData(workspace.id, extractedContent)
  }

  // 若存在待持久化的 entries，则写入 IndexedDB
  try {
    const pending = (window as any).__lvPendingEntries as { path: string; type: 'file' | 'dir'; isBinary: boolean; bytes?: Uint8Array }[] | undefined
    console.log('检查待持久化条目:', pending ? pending.length : 'undefined')
    if (pending && pending.length > 0) {
      console.log('开始持久化解压条目数量:', pending.length)
      console.log('工作区ID:', workspace.id)
      console.log('前5个条目样例:', pending.slice(0, 5).map(e => ({ path: e.path, type: e.type, isBinary: e.isBinary })))
      await saveWorkspaceEntries(workspace.id, pending)
      console.log('持久化完成')
      ;(window as any).__lvPendingEntries = undefined
    } else {
      console.log('没有待持久化的条目')
    }
  } catch (e) {
    console.error('持久化解压条目失败:', e)
  }
  
  // 切换到新创建的工作区
  workspaceStore.setCurrentWorkspace(workspace.id)
  showCreateWorkspace.value = false
  
  // 重置表单
  newWorkspace.name = ''
  newWorkspace.type = 'general'
  modalFileList.value = []
  
  // 直接跳转到日志查看页面
  router.push('/workspace/viewer')
  } catch (error) {
    console.error('从模态框创建工作区失败:', error)
    
    // 显示用户友好的错误信息
    const errorMessage = error instanceof Error ? error.message : '未知错误'
    alert(`创建工作区失败: ${errorMessage}`)
  } finally {
    isCreating.value = false
  }
}

function formatDate(dateString: string): string {
  return new Date(dateString).toLocaleDateString('zh-CN')
}

// 解压gz文件，支持 .gz 与 .tar.gz
async function extractGzFile(file: File) {
  try {
    console.log('开始解压gz文件:', file.name, '大小:', (file.size / 1024 / 1024).toFixed(2), 'MB')
    
    // 检查文件大小限制（放宽至 512MB）
    const maxSize = 512 * 1024 * 1024 // 512MB
    if (file.size > maxSize) {
      throw new Error(`文件过大 (${(file.size / 1024 / 1024).toFixed(2)}MB)，最大支持 512MB`)
    }
    
    // 异步读取并解压
    return new Promise<string>((resolve, reject) => {
      const reader = new FileReader()

      reader.onload = async (e) => {
        try {
          const arrayBuffer = e.target?.result as ArrayBuffer
          console.log('文件读取完成，开始解压，大小:', (arrayBuffer.byteLength / 1024 / 1024).toFixed(2), 'MB')

          const compressed = new Uint8Array(arrayBuffer)
          // 使用 pako 解压得到二进制
          const inflated: Uint8Array = pako.inflate(compressed)

          // 检测是否为 tar 归档（ustar 标记在偏移 257-262）
          const isTar = inflated.length > 262 &&
            inflated[257] === 117 && // 'u'
            inflated[258] === 115 && // 's'
            inflated[259] === 116 && // 't'
            inflated[260] === 97 &&  // 'a'
            inflated[261] === 114 && // 'r'
            (inflated[262] === 0 || inflated[262] === 32)

          if (isTar || /\.tar\.gz$/i.test(file.name)) {
            console.log('检测到 tar.gz，开始解析 tar 归档')
            const { linearText, entries } = parseTarToLinearTextWithEntries(inflated)
            console.log('tar 解析完成，线性文本长度:', (linearText.length / 1024 / 1024).toFixed(2), 'MB')
            // 先暂存在 window 级变量，待创建工作区成功后持久化
            ;(window as any).__lvPendingEntries = entries
            resolve(linearText)
            return
          }

          // 非 tar.gz，当作纯文本处理
          const decoder = new TextDecoder('utf-8')
          const text = decoder.decode(inflated)
          console.log('解压完成（纯文本），解压后大小:', (text.length / 1024 / 1024).toFixed(2), 'MB')
          resolve(text)
        } catch (error) {
          console.error('解压失败:', error)
          reject(new Error(`解压失败: ${error}`))
        }
      }

      reader.onerror = () => {
        reject(new Error('文件读取失败'))
      }

      reader.readAsArrayBuffer(file)
    })
  } catch (error) {
    console.error('gz文件处理失败:', error)
    throw error
  }
}

// 解析 tar：返回线性文本 + 可持久化的条目
function parseTarToLinearTextWithEntries(tarData: Uint8Array): { linearText: string; entries: { path: string; type: 'file' | 'dir'; isBinary: boolean; bytes?: Uint8Array }[] } {
  const decoder = new TextDecoder('utf-8')
  let offset = 0
  const blockSize = 512
  let resultParts: string[] = []
  let filesParsed = 0
  let pendingLongName: string | null = null
  let pendingPaxPath: string | null = null
  const TOTAL_TEXT_LIMIT = 600 * 1024 * 1024 // 总体最多 600MB 文本
  const entries: { path: string; type: 'file' | 'dir'; isBinary: boolean; bytes?: Uint8Array }[] = []

  // 判断是否为可能的文本文件（避免把二进制/子压缩包塞进文本）
  const isLikelyText = (bytes: Uint8Array, fileName: string): boolean => {
    // 跳过常见压缩包
    if (/\.(gz|tgz|tar|zip|7z|bz2|xz)$/i.test(fileName)) return false
    const sample = bytes.subarray(0, Math.min(4096, bytes.length))
    let controlCount = 0
    for (let i = 0; i < sample.length; i++) {
      const c = sample[i]
      // 允许常见换行符、制表符
      if (c === 9 || c === 10 || c === 13) continue
      if (c < 32 || c === 0) controlCount++
    }
    // 控制字符比例过高，视为二进制
    return controlCount / Math.max(1, sample.length) < 0.02
  }

  while (offset + blockSize <= tarData.length) {
    // 读取头部
    const header = tarData.subarray(offset, offset + blockSize)
    const allZero = header.every(b => b === 0)
    if (allZero) break

    // 基本头信息
    let name = decoder.decode(header.subarray(0, 100)).replace(/\u0000.*$/, '').trim()
    const sizeOctal = decoder.decode(header.subarray(124, 136)).replace(/\u0000.*$/, '').trim()
    const typeFlag = header[156] // ASCII code
    const magic = decoder.decode(header.subarray(257, 263)) // 'ustar\0' or 'ustar  '
    const prefix = magic.startsWith('ustar')
      ? decoder.decode(header.subarray(345, 500)).replace(/\u0000.*$/, '').trim()
      : ''

    let size = parseInt(sizeOctal || '0', 8)

    // GNU LongName 支持（typeflag = 'L' -> 76）
    if (typeFlag === 76) {
      offset += blockSize
      const nameBytes = tarData.subarray(offset, offset + size)
      pendingLongName = decoder.decode(nameBytes).replace(/\u0000.*$/, '').trim()
      // 跳到下一个 512 对齐
      const remainder = size % blockSize
      const advance = remainder === 0 ? size : size + (blockSize - remainder)
      offset += advance
      // 继续读取下一头部，实际文件条目会紧随其后
      continue
    }

    // PAX extended header（typeflag = 'x' -> 120），用于提供下一条目的长路径等信息
    if (typeFlag === 120) {
      offset += blockSize
      const paxBytes = tarData.subarray(offset, offset + size)
      const paxText = decoder.decode(paxBytes)
      // 解析格式: "LEN key=value\n"
      pendingPaxPath = null
      const lines = paxText.split('\n')
      for (const line of lines) {
        const spaceIdx = line.indexOf(' ')
        if (spaceIdx === -1) continue
        const kv = line.slice(spaceIdx + 1)
        const eqIdx = kv.indexOf('=')
        if (eqIdx === -1) continue
        const key = kv.slice(0, eqIdx)
        const value = kv.slice(eqIdx + 1)
        if (key === 'path') {
          pendingPaxPath = value
        }
      }
      const remainder = size % blockSize
      const advance = remainder === 0 ? size : size + (blockSize - remainder)
      offset += advance
      // 下一条目将使用 pendingPaxPath
      continue
    }

    // 组合完整文件名
    let fullName = name
    if (pendingLongName) {
      fullName = pendingLongName
      pendingLongName = null
    } else if (pendingPaxPath) {
      fullName = pendingPaxPath
      pendingPaxPath = null
    } else if (prefix) {
      fullName = `${prefix}/${name}`
    }

    offset += blockSize

    // 目录或空条目
    if (!fullName || typeFlag === 53 /* '5' 目录 */) {
      entries.push({ path: fullName || '', type: 'dir', isBinary: false })
      const skip = Math.ceil(size / blockSize) * blockSize
      offset += skip
      continue
    }

    const fileBytes = tarData.subarray(offset, offset + size)

    if (isLikelyText(fileBytes, fullName)) {
      const content = decoder.decode(fileBytes)
      resultParts.push(fullName)
      resultParts.push(content)
      entries.push({ path: fullName, type: 'file', isBinary: false, bytes: fileBytes })
      filesParsed++
    } else {
      // 非文本，仍保留路径占位，便于调试定位
      resultParts.push(fullName)
      resultParts.push('[binary skipped]')
      entries.push({ path: fullName, type: 'file', isBinary: true, bytes: fileBytes })
    }

    // 前进到下一个 512 对齐
    const remainder = size % blockSize
    const advance = remainder === 0 ? size : size + (blockSize - remainder)
    offset += advance

    // 体积保护：最多聚合 TOTAL_TEXT_LIMIT 文本
    const currentSize = resultParts.reduce((acc, p) => acc + p.length, 0)
    if (currentSize > TOTAL_TEXT_LIMIT) {
      console.warn('tar 展开文本超过上限，已截断')
      break
    }
  }

  console.log('parseTarToLinearText - 解析文件数:', filesParsed)
  return { linearText: resultParts.join('\n'), entries }
}

// 解压模态框中的gz文件
async function extractModalGzFile(file: File) {
  try {
    console.log('开始解压模态框文件:', file.name)
    
    // 使用pako库解压gz文件
    const arrayBuffer = await file.arrayBuffer()
    const uint8Array = new Uint8Array(arrayBuffer)
    
    // 使用pako库解压gz文件
    const decompressed = pako.inflate(uint8Array, { to: 'string' })
    
    console.log('模态框文件解压成功，大小:', decompressed.length)
    
    // 创建解压后的文件对象
    const extractedFile = new File([decompressed], file.name.replace('.gz', ''), {
      type: 'text/plain'
    })
    
    // 更新模态框文件列表，用解压后的文件替换原文件
    modalFileList.value = [{
      id: modalFileList.value[0]?.id || Date.now().toString(),
      name: extractedFile.name,
      status: 'finished',
      file: extractedFile
    }]
    
    console.log('模态框解压完成，文件已更新:', extractedFile.name)
    
  } catch (error) {
    console.error('模态框解压文件失败:', error)
    // 解压失败时保持原文件
  }
}
</script>

<style scoped>
.workspace-management {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 20px;
}

/* 创建工作区样式 */
.create-workspace-section {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 80vh;
  padding: 60px 40px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

.create-workspace-form {
  width: 100%;
  max-width: 800px;
  background: white;
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
  padding: 60px;
}

.form-header {
  text-align: center;
  margin-bottom: 48px;
}

.header-icon {
  margin-bottom: 24px;
}

.form-header h2 {
  margin: 0 0 16px 0;
  font-size: 36px;
  font-weight: 700;
  color: var(--n-text-color);
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.form-header p {
  margin: 0;
  color: var(--n-text-color-3);
  font-size: 18px;
  line-height: 1.6;
}

.workspace-form {
  width: 100%;
}

.upload-section {
  width: 100%;
}

.upload-content {
  text-align: center;
  padding: 40px;
  border: 2px dashed #d9d9d9;
  border-radius: 12px;
  transition: all 0.3s ease;
}

.upload-content:hover {
  border-color: #18a058;
  background-color: #f6ffed;
}

.upload-text {
  margin: 16px 0 8px 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--n-text-color);
}

.upload-hint {
  margin: 0;
  font-size: 14px;
  color: var(--n-text-color-3);
}

.file-info {
  margin-top: 12px;
  text-align: center;
}

/* 工作区概览样式 */
.workspace-overview-section {
  width: 100%;
}

.page-header {
  margin-bottom: 40px;
  padding: 40px 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 16px;
  color: white;
}

.header-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 40px;
  padding: 0 40px;
}

.title-section h1 {
  margin: 0 0 12px 0;
  font-size: 36px;
  font-weight: 700;
  color: white;
}

.subtitle {
  margin: 0;
  color: rgba(255, 255, 255, 0.9);
  font-size: 18px;
  line-height: 1.6;
}

.workspace-overview {
  margin-bottom: 40px;
}

.workspace-card {
  cursor: pointer;
  transition: all 0.3s ease;
  height: 100%;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid #f0f0f0;
}

.workspace-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}

.workspace-card.active {
  border: 3px solid var(--n-primary-color);
  box-shadow: 0 8px 16px rgba(24, 160, 88, 0.2);
}

.workspace-card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 24px;
  padding: 24px 24px 0 24px;
}

.workspace-info h3 {
  margin: 0 0 12px 0;
  font-size: 20px;
  font-weight: 700;
  color: var(--n-text-color);
}

.workspace-info p {
  margin: 0 0 12px 0;
  color: var(--n-text-color-3);
  font-size: 14px;
  line-height: 1.6;
}

.workspace-stats {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0 24px 24px 24px;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 14px;
  padding: 8px 0;
  border-bottom: 1px solid #f5f5f5;
}

.stat-item:last-child {
  border-bottom: none;
}

.stat-label {
  color: var(--n-text-color-3);
  font-weight: 500;
}

.stat-value {
  font-weight: 700;
  color: var(--n-text-color);
  font-size: 16px;
}

.current-workspace-section {
  margin-top: 40px;
}

.feature-card {
  height: 100%;
  border-radius: 12px;
  transition: all 0.3s ease;
}

.feature-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}

.feature-card p {
  margin: 0;
  color: var(--n-text-color-3);
  font-size: 14px;
  line-height: 1.6;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .header-content {
    flex-direction: column;
    gap: 16px;
  }
  
  .workspace-card-header {
    flex-direction: column;
    gap: 12px;
  }
  
  .workspace-actions {
    width: 100%;
  }
}
</style> 